#pragma once

#include <iostream>
#include <functional>
#include <string>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include <signal.h>
#include <pthread.h>
#include "protocol.hpp"
#include "log.hpp"

typedef std::function<void(const Request &, Response *)> func_t;
const int gbacklog = 5;
enum
{
    USAGE_ERR = 1,
    SOCKET_ERR,
    BIND_ERR,
    LISTEN_ERR,
};

void handlerEnter(int sock, func_t func)
{
    std::string inbuffer;
    while (true)
    {
        // 1.接收请求
        // 1.1如何保证接收一个完整的请求
        std::string req_str, req_content;
        if (!recvPackage(sock, inbuffer, &req_str))
            return;
        // 1.2提取正文
        if (!deLength(req_str, &req_content))
            return;


        // 2.将请求反序列化
        Request req;
        if (!req.deserialize(req_content))
            return;
        
        logMessage(NORMAL, "收到计算请求: %s\n", req_content.c_str());

        // 3.处理任务
        Response resp;
        func(req, &resp);

        // 4.将响应序列化
        std::string resp_str;
        if (!resp.serialize(&resp_str))
            return;

        logMessage(NORMAL, "响应序列化结果: %s\n", resp_str.c_str());

        // 5.发送响应
        // 5.1.添加格式
        std::string send_string = enLength(resp_str);
        send(sock, send_string.c_str(), send_string.size(), 0);
    }
}

class calServer
{
public:
    calServer(uint16_t port) : _port(port)
    {
    }

    void initServer()
    {
        // 1.创建套接字
        _listensockfd = socket(AF_INET, SOCK_STREAM, 0); // tcp是字节流传输的
        if (_listensockfd < 0)
        {
            logMessage(FATAL, "Create socket failed");
            exit(SOCKET_ERR);
        }
        logMessage(NORMAL, "Create socket success");

        // 2.bind套接字
        struct sockaddr_in server;
        server.sin_family = AF_INET;
        server.sin_port = htons(_port);
        server.sin_addr.s_addr = INADDR_ANY;
        if (bind(_listensockfd, (struct sockaddr *)&server, sizeof(server)) < 0)
        {
            logMessage(FATAL, "Bind failed");
            exit(BIND_ERR);
        }
        logMessage(NORMAL, "Bind success");

        // 3.listen 监听连接
        if (listen(_listensockfd, gbacklog) < 0)
        {
            logMessage(FATAL, "Listen failed");
            exit(LISTEN_ERR);
        }
        logMessage(NORMAL, "Listenning...");
    }

    void start(func_t func)
    {

        for (;;)
        {
            // 4.获取新连接
            struct sockaddr_in peer;
            socklen_t len = sizeof(peer);
            int sockfd = accept(_listensockfd, (struct sockaddr *)&peer, &len);
            if (sockfd < 0)
            {
                logMessage(ERROR, "Accept failed, next");
                continue;
            }
            logMessage(NORMAL, "accept sock success,sock: %d", sockfd);

            // version 2(多进程)
            // 1)双fork解决僵尸，用孤儿进程执行任务
            pid_t id = fork();
            if (id == 0)
            {
                close(_listensockfd);
                if (fork() > 0)
                    exit(0);
                handlerEnter(sockfd, func);
                close(sockfd);
                exit(0);
            }
            close(sockfd);

            int ret = waitpid(id, nullptr, 0);
            if (ret > 0)
                logMessage(NORMAL, "wait success");
        }
    }

    ~calServer()
    {
    }

private:
    int _listensockfd;
    uint16_t _port;
};